package com.hyd.tweet.user;

import com.hyd.tweet.PMF;
import com.hyd.tweet.util.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.jdo.Extent;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;
import java.util.ArrayList;
import java.util.List;

/**
 * (description)
 *
 * @author yiding.he
 */
@SuppressWarnings({"unchecked"})
public class UserManager {

    static final Logger log = LoggerFactory.getLogger(UserManager.class);

    public static void preloadUsers() {
        PersistenceManager pm = PMF.get().getPersistenceManager();
        pm.setDetachAllOnCommit(true);
        pm.currentTransaction().begin();

        List<String> accountList = new ArrayList<String>();

        Extent<User> extent = pm.getExtent(User.class, false);
        try {
            for (User user : extent) {
                User detachedUser = pm.detachCopy(user);

                String account = detachedUser.getAccount();
                accountList.add(account);
                Cache.put(account, detachedUser);
            }

            Cache.put("accountList", accountList);
        } finally {
            extent.closeAll();
            pm.currentTransaction().commit();
            pm.close();
        }
    }

    ///////////////////////////////////////////////////////

    // 同一个 Gmail 存在多条记录不会导致该用户收到多次重复消息，因为
    // 读取出来的用户信息保存在 Cache 中，对每一个 Gmail 只会保存一个值
    @SuppressWarnings({"unchecked"})
    public static User getUser(String account) {
        User user = null;
        try {
            user = Cache.get(account);

            if (user == null) {
                try {
                    user = queryUser(account);

                    if (user != null) {
                        Cache.put(account, user);
                    }
                } catch (Exception e) {
                    log.error("从数据库取失败", e);
                }
            }
        } catch (Exception e) {
            log.warn("从缓存取 user 失败", e);
        }

        return user;
    }

    private static User queryUser(String account) {
        PersistenceManager pm = PMF.get().getPersistenceManager();

        Query query = pm.newQuery(User.class, "account == accountParam");
        query.declareParameters("String accountParam");

        try {
            List<User> result = (List<User>) query.execute(account);
            removeDuplicate(pm, result);

            User user = null;
            if (!result.isEmpty()) {
                user = pm.detachCopy(result.get(0));
            }

            return user;
        } finally {
            query.closeAll();
            pm.close();
        }
    }

    private static void removeDuplicate(PersistenceManager pm, List<User> result) {
        // 出现重复记录的话，删除多余的。
        if (result.size() > 1) {
            pm.deletePersistent(result.get(1));
        }
    }

    public static void saveNewUser(String account, String token, String tokenSecret) {
        log.info("添加用户记录：" + account);

        User user = new User();
        user.setAccount(account);
        user.setToken(token);
        user.setTokenSecret(tokenSecret);
        user.setMessageStatus("stopped");

        user.saveToCache();
        persistentUser(user);

        List<String> accountList = tryGetAccountList();
        if (accountList != null) {
            accountList.add(account);
            putAccountListToCache(accountList);
        }
    }

    private static void persistentUser(User user) {
        if (user == null) {
            return;
        }

        PersistenceManager pm = PMF.get().getPersistenceManager();
        pm.currentTransaction().begin();
        try {
            pm.makePersistent(user);
            pm.currentTransaction().commit();
        } catch (RuntimeException e) {
            pm.currentTransaction().rollback();
            throw e;
        } finally {
            pm.close();
        }
    }

    public static void deleteUser(String account) {
        User user = getUser(account);
        if (user == null) {
            return;
        }

        Cache.remove(user.getAccount());
        unpersistentUser(user);

        List<String> accountList = tryGetAccountList();
        if (accountList != null) {
            accountList.remove(account);
            putAccountListToCache(accountList);
        }
    }

    private static void putAccountListToCache(List<String> accountList) {
        Cache.put("accountList", accountList);
    }

    private static void unpersistentUser(User user) {
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Transaction transaction = pm.currentTransaction();
        try {
            transaction.begin();
            pm.deletePersistent(user);
            transaction.commit();
        } finally {
            if (transaction.isActive()) {
                transaction.rollback();
            }
            pm.close();
        }
    }

    ///////////////////////////////////////////////////////

    @SuppressWarnings({"unchecked"})
    public static List<String> next(int size) {
        List<String> accountList = tryGetAccountList();

        if (accountList.isEmpty()) {
            return new ArrayList<String>();
        }

        if (size >= accountList.size()) {
            return new ArrayList<String>(accountList);
        } else {

            int rollPointer = Cache.containsKey("user_iterator_pointer") ?
                    (Integer) Cache.get("user_iterator_pointer") : 0;

            List<String> result = new ArrayList<String>();
            int counter = 0;

            while (counter < size) {
                if (rollPointer >= accountList.size()) {
                    rollPointer = 0;
                }

                result.add(accountList.get(rollPointer));
                rollPointer = (rollPointer + 1) % accountList.size();
                counter++;
            }

            Cache.put("user_iterator_pointer", rollPointer);
            return result;
        }
    }

    public static void persistentAllUsers() {
        List<String> accountList = tryGetAccountList();

        if (accountList.isEmpty()) {
            return;
        }

        PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
            for (String account : accountList) {
                User user = getUser(account);
                pm.makePersistent(user);
            }
        } finally {
            pm.close();
        }
    }

    private static List<String> tryGetAccountList() {
        List<String> accountList = Cache.get("accountList");

        if (accountList == null) {
            preloadUsers();
            log.warn("Account list missing, reload.");
            accountList = Cache.get("accountList");
        }

        return accountList;
    }
}
